﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using l1cs.server.model.Instance;
using l1cs.server.model.map;
using l1cs.server.serverpackets;
using System.Threading;
using l1cs.server.utils;

namespace l1cs.server.model
{
    public class L1Teleport
    {
        private static Logger _log = Logger.getLogger( typeof( L1Teleport ).FullName );

        // テレポートスキルの種類
        public const int TELEPORT = 0;

        public const int CHANGE_POSITION = 1;

        public const int ADVANCED_MASS_TELEPORT = 2;

        public const int CALL_CLAN = 3;

        // 順番にteleport(白), change position e(青), ad mass teleport e(赤), call clan(緑)
        public static int[] EFFECT_SPR = { 169, 2235, 2236, 2281 };

        public static int[] EFFECT_TIME = { 280, 440, 440, 1120 };

        private L1Teleport() { }

        public static void teleport( L1PcInstance pc, L1Location loc, int head, bool effectable )
        {
            teleport( pc, loc.getX(), loc.getY(), (short)loc.getMapId(), head, effectable, TELEPORT );
        }

        public static void teleport( L1PcInstance pc, L1Location loc, int head, bool effectable, int skillType )
        {
            teleport( pc, loc.getX(), loc.getY(), (short)loc.getMapId(), head, effectable, skillType );
        }

        public static void teleport( L1PcInstance pc, int x, int y, short mapid, int head, bool effectable )
        {
            teleport( pc, x, y, mapid, head, effectable, TELEPORT );
        }

        public static void teleport( L1PcInstance pc, int x, int y, short mapId, int head, bool effectable, int skillType )
        {
            pc.sendPackets( new S_Paralysis( S_Paralysis.TYPE_TELEPORT_UNLOCK, false ) );

            // エフェクトの表示
            if ( effectable && ( skillType >= 0 && skillType <= EFFECT_SPR.Length ) )
            {
                S_SkillSound packet = new S_SkillSound( pc.getId(), EFFECT_SPR[skillType] );
                pc.sendPackets( packet );
                pc.broadcastPacket( packet );

                // テレポート以外のsprはキャラが消えないので見た目上送っておきたいが
                // 移動中だった場合クラ落ちすることがある
                // if (skillType != TELEPORT) {
                // pc.sendPackets(new S_DeleteNewObject(pc));
                // pc.broadcastPacket(new S_DeleteObjectFromScreen(pc));
                // }

                Thread.Sleep( (int)( EFFECT_TIME[skillType] * 0.7 ) );
            }

            pc.setTeleportX( x );
            pc.setTeleportY( y );
            pc.setTeleportMapId( mapId );
            pc.setTeleportHeading( head );
            if ( Config.SEND_PACKET_BEFORE_TELEPORT )
            {
                pc.sendPackets( new S_Teleport( pc ) );
            }
            else
            {
                Teleportation.staticTeleportation( pc );
            }
        }

        /*
         * targetキャラクターのdistanceで指定したマス分前にテレポートする。指定されたマスがマップでない場合何もしない。
         */
        public static void teleportToTargetFront( L1Character cha, L1Character target, int distance )
        {
            int locX = target.getX();
            int locY = target.getY();
            int heading = target.getHeading();
            L1Map map = target.getMap();
            short mapId = target.getMapId();

            // ターゲットの向きからテレポート先の座標を決める。
            switch ( heading )
            {
                case 1:
                    locX += distance;
                    locY -= distance;
                    break;

                case 2:
                    locX += distance;
                    break;

                case 3:
                    locX += distance;
                    locY += distance;
                    break;

                case 4:
                    locY += distance;
                    break;

                case 5:
                    locX -= distance;
                    locY += distance;
                    break;

                case 6:
                    locX -= distance;
                    break;

                case 7:
                    locX -= distance;
                    locY -= distance;
                    break;

                case 0:
                    locY -= distance;
                    break;

                default:
                    break;

            }

            if ( map.isPassable( locX, locY ) )
            {
                if ( cha is L1PcInstance )
                {
                    teleport( (L1PcInstance)cha, locX, locY, mapId, cha.getHeading(), true );
                }
                else if ( cha is L1NpcInstance )
                {
                    ( (L1NpcInstance)cha ).teleport( locX, locY, cha.getHeading() );
                }
            }
        }

        public static void randomTeleport( L1PcInstance pc, bool effectable )
        {
            // まだ本サーバのランテレ処理と違うところが結構あるような・・・
            L1Location newLocation = pc.getLocation().randomLocation( 200, true );
            int newX = newLocation.getX();
            int newY = newLocation.getY();
            short mapId = (short)newLocation.getMapId();

            L1Teleport.teleport( pc, newX, newY, mapId, 5, effectable );
        }
    }
}
